module mod_elglike
use mod_elgdata
use mod_elglike_element
use mod_params

implicit none

  
  !
  ! Elg-likelihood
  !
  ! Contains methods for conversion between various structures, convolusion, automatic loading and saving of maps & power spectra,
  ! timer functions, parameter file usage, output and misc
  !
  ! (c) Nicolaas E. Groeneboom
  !     leuat@irio.co.uk
  !     http://www.irio.co.uk
  !

  type, public :: t_elglike
     real, dimension(:), allocatable :: val
     integer :: lmax
     real :: likelihood
  end type t_elglike
  
contains  

subroutine elglike_initialize(elglike, lmax)
  type(t_elglike), intent(inout) :: elglike
  integer, intent(inout) :: lmax

  allocate(elglike%val(lmax))
  elglike%val = 0
  elglike%lmax = Lmax

end subroutine elglike_initialize

subroutine elglike_calculate_likelihood_brute(elglike, params)
  real*8, dimension(6), intent(inout) :: params
  type(t_elglike), intent(inout) :: elglike
  integer :: i
  real*8 :: l
  type(t_elglike_element) :: elg

  call elglike_element_initialize(elg);

  do i=1, global_lmax
     l = i
     params(6) = l
!     call elglike_element_setup_matrix(elg, params(1:5));
     call elglike_element_calculate_likelihood(elg, l, global_elgdata%elements(i));
     elglike%val(i) = elg%likelihood
     write (*,*) "Likelihood element ",i,elg%likelihood
  end do

end subroutine elglike_calculate_likelihood_brute

     !write(*,*) "Listener..", listeners

subroutine elglike_save(elg, filename) 
  character(len=*), intent(in) :: filename
  type(t_elglike), intent(in) :: elg

  integer :: f,i,j,k

  f = 14
    
  open(unit=f,file=filename,action='write',status='replace')
  do i=1, elg%lmax
     write(f,*) i, elg%val(i)
  end do
  close(f)


end subroutine elglike_save



subroutine elglike_calculate_likelihood_cheat(elglike, proposed)
  type(t_params), intent(inout) :: proposed
  type(t_elglike), intent(inout) :: elglike
 
  double precision val, sigma, mean

  sigma = 0.05
  mean = 0.3

  val = exp(-(proposed%params(1)-mean)**2/sigma**2)

  elglike%likelihood  = val 


end subroutine elglike_calculate_likelihood_cheat



subroutine elglike_calculate_likelihood_master(elglike, params)


include 'mpif.h'

  type(t_params), intent(inout) :: params
  type(t_params), dimension(global_num_procs) :: sendparams
  type(t_elglike), intent(inout) :: elglike
  integer :: i, ll, filled, currentProcess, listeners, ierr, r
  real*4 :: l
  type(t_elglike_element) :: elg
  integer, dimension(:), allocatable :: reqs
  logical :: flag
  integer, dimension(MPI_STATUS_SIZE*2) :: status
  double precision, dimension(global_num_procs*2) :: recv


  call elglike_element_initialize(elg);

  allocate(reqs(0:global_num_procs));

  listeners = 0
  filled = -1
  reqs = -10
  l = 1
  currentProcess = global_id_master+1
  do while (filled==-1)

     if (listeners<global_num_procs-1 .and. l<global_lmax) then
        call params_copy(params, sendparams(currentProcess))

        sendparams(currentProcess)%params(6) = l
        !write(*,*) "Sending to", currentprocess, l
        call MPI_ISEND( sendparams(currentProcess)%params, 10, MPI_DOUBLE_PRECISION, currentProcess, &
             & global_tag, MPI_COMM_WORLD, reqs(currentProcess), ierr) 
        ll = l
        !call MPI_IRECV(elglike%val(ll), 1, MPI_REAL, currentProcess, global_tag, MPI_COMM_WORLD, reqs(currentProcess), ierr)   
        call MPI_IRECV(recv(currentProcess*2), 2, MPI_DOUBLE_PRECISION, &
             &currentProcess, global_tag, MPI_COMM_WORLD, reqs(currentProcess), ierr)   

!        write(*,*) "Creating listener for ", reqs(currentProcess

        listeners = listeners +1


        currentProcess = currentProcess+1
        if (currentProcess == global_num_procs)  currentProcess = global_id_master+1

        l = l+global_l_step
     end if
     !stop

        do i=global_id_master+1, global_num_procs
          if (reqs(i) .ne. -10) then
              call mpi_test(reqs(i), flag, status, global_ierr)
              !write(*,*) "Testing", flag,i 
              if (flag .eqv. .true.) then
                 listeners = listeners-1
                 
                 write(*,*) "Received from process", i, "values", recv(i*2)
                 reqs(i) = -10
                 elglike%val(recv(i*2)) = recv(i*2 +1)
                 call elglike_save(elglike, "test.txt")
              end if
           end if
      end do

     !filled = 1
      if (l>=global_lmax .and. listeners==0) filled = 1
     !o i=1, global_lmax
     !   if (elglike%val(i)==0) filled=-1
     !end do

     
     !write(*,*) "not yet filled"
  end do
  elglike%likelihood = exp(0.001*-sum(elglike%val))
  write(*,*) "Final likelihood:", elglike%likelihood
  deallocate(reqs)
  
  

 ! do i=1, global_lmax
 !    l = i
 !    params(6) = l
 !    call elglike_element_setup_matrix(elg, params);
 !    call elglike_element_calculate_likelihood(elg, l, global_elgdata%elements(i));
 !    elglike%val(i) = elg%likelihood
 !     write (*,*) "Likelihood element ",i,elg%likelihood
 !  end do

end subroutine elglike_calculate_likelihood_master


end module mod_elglike


